Ext.onReady(function() {

/**
 * @class AsyncLoader
 * @extends Ext.tree.TreeLoader
 */
var AsyncLoader = Ext.extend(Ext.tree.TreeLoader, {
  dataUrl : '#',

  /* abstract */
  doAsyncLoad : Ext.emptyFn,

  // overriding TreeLoader's methods
  requestData : function(node, callback){
    if (this.fireEvent("beforeload", this, node, callback) !== false){
      var _this = this;
      this.doAsyncLoad(node, {
        onSuccess: function(results) { _this.handleResponse(results, node, callback) },
        onFailure: function(error) { _this.handleFailure(error, node, callback) }
      })
    } else {
      // if the load is cancelled, make sure we notify
      // the node that we are done
      if (typeof callback == "function"){
        callback();
      }
    }
  },

  handleResponse : function(results, node, callback){
    try {
      node.beginUpdate();
      for(var i=0, len=results.length; i<len; i++){
        var n = this.createNode(results[i]);
        if(n){
          node.appendChild(n);
        }
      }
      node.endUpdate();
      if (typeof callback == "function"){
        callback(this, node);
      }
      this.fireEvent("load", this, node, results);
    } catch(e) {
      this.handleFailure(e);
    }
  },

  handleFailure : function(error, node, callback){
    this.fireEvent("loadexception", this, node, error);
    if (typeof callback == "function"){
      callback(this, node);
    }
  }

});


/**
 * @class MakeRequestLoader 
 * @extends AsyncLoader
 */
var MakeRequestLoader = Ext.extend(AsyncLoader, {

  doAsyncLoad : function(node, callback) {
    if (!node.attributes.value) {
      var params = node.attributes.params;
      // using makeRequest call
      makeRequest(params, {
        onSuccess : function (o) { 
          node.attributes.value = o;
          callback.onSuccess(describeProperties(o));
        },
        onFailure : function(error) {
          if (error) alert(error);
          callback.onFailure();
        }
      });
    } else {
      callback.onSuccess(describeProperties(node.attributes.value))
    }

    function describeProperties(o) {
      var ret = [];
      if (o && o.constructor == Array) {
        for (var i=0,len=o.length; i<len; i++) {
          ret.push(createNodeConfig('['+i+']', o[i]));
        }
      } else if (typeof o == "object" && o != null) {
        for (var key in o) {
          ret.push(createNodeConfig(key, o[key]));
        }
      }
      return ret;
    } 

    function createNodeConfig(name, value) {
      var leaf = (value == null || 
                  value.constructor == String || value.constructor == Boolean ||
                  value.constructor == Number || value.constructor == Date);
      return {
        text : leaf ? name + ' : ' + escapeHTML(value) : name,
        value : value,
        leaf : leaf 
      };
    }

    function escapeHTML(str) {
      return (''+str).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
    }

  }

});


/**
 *
 */
var baseUrl = (function() {
  var scripts = document.getElementsByTagName('script');
  for (var i=0; i<scripts.length; i++) {
    var script = scripts[i];
    var m = (script.src || '').match(/^(.*)\/ext-all(-debug)?.js$/);
    if (m) return m[1]
  }
  return null;
})();

if (baseUrl) Ext.BLANK_IMAGE_URL = baseUrl + '/resources/images/default/s.gif';

/**
 *
 */
if (typeof OAuthServices == 'undefined') {
  OAuthServices = [ 'google', 'twitter', 'friendfeed', 'linkedin', 'smartfm' ];
}

//
var requestForm = {
  id : 'requestForm',
  xtype : 'form',
  title : 'Request',
  frame : true,
  autoHeight : true,
  defaultType : 'textfield',
  labelWidth : 150,
  items : [{ 
    itemId : 'url',
    name : 'url',
    fieldLabel : 'Endpoint URL',
    anchor : '100%' 
  }, { 
    xtype : 'combo',
    itemId : 'contentType', 
    name : 'contentType',
    fieldLabel : 'Content Type',
    triggerAction : 'all',
    forceSelection : true,
    editable : false,
    value : 'JSON',
    store : ['JSON','FEED','DOM','TEXT']
  }, {
    xtype : 'fieldset',
    layout : 'form',
    title : 'OAuth Parameters',
    collapsible : true,
    collapsed : true,
    autoHeight : true,
    items : [{
      xtype : 'combo',
      itemId : 'OAUTH_SERVICE_NAME',
      name : 'OAUTH_SERVICE_NAME', 
      fieldLabel : 'Service Name',
      triggerAction : 'all',
      forceSelection : true,
      editable : false,
      store : [''].concat(OAuthServices)
    }],
    listeners : {
      expand : resizeFrame,
      collapse : resizeFrame
    }
  }],
  buttons : [{
    text : 'Request',
    handler : function(btn) { 
      var params = btn.ownerCt.getForm().getValues();
      doRequest(params);
    }
  }]
};

//
var requestResult = {
  id : 'resultArea',
  title : 'Response Result',
  layout : 'border',
  height : 400,
  items : [{
    id : 'resultContainer',
    region : 'center',
    border : false,
    layout : 'card',
    activeItem : 1,
    items : [{
      id : 'resultTree',
      xtype : 'treepanel',
      animate : false,
      autoScroll : true,
      root : new Ext.tree.AsyncTreeNode({ text : 'result' }),
      loader : new MakeRequestLoader(),
      listeners : {
        click : function(node, e) {
          if (resultDump.isVisible()) {
            Ext.fly('dumparea').dom.value = Ext.util.JSON.encode(node.attributes.value);
          }
        }
      }
    }, {
      id : 'resultTextArea',
      xtype : 'textarea'
    }]
  }, {
    id : 'resultDump',
    region : 'east',
    title : 'JSON Dump',
    width : '200',
    collapsible : true,
    split : true,
    layout : 'anchor',
    items : {
      xtype : 'textarea',
      id : 'dumparea',
      anchor : '100% 100%'
    },
    listeners : {
      afterlayout : resizeFrame
    }
  }]
};


// panel init
new Ext.Panel({
  renderTo : 'root',
  border : false,
  autoHeight : true,
  layout : 'anchor',
  items : {
    layout : 'anchor',
    defaults : { anchor : '100%' },
    items : [ requestForm, requestResult ]
  }
});

//
var resultContainer = Ext.getCmp('resultContainer');
var resultDump = Ext.getCmp('resultDump');
var resultTree = Ext.getCmp('resultTree');
var resultTextArea = Ext.getCmp('resultTextArea');


function resizeFrame() {
  if (gadgets.window && gadgets.window.adjustHeight) {
    gadgets.window.adjustHeight();
  }
}

function doRequest(params) {
  if (params.contentType=='TEXT') {
    resultContainer.getLayout().setActiveItem(1);
    makeRequest(params, {
      onSuccess : function (text) { resultTextArea.setValue(text); },
      onFailure : function(error) { if (error) alert(error); }
    });
  } else {
    resultContainer.getLayout().setActiveItem(0);
    var root = resultTree.getRootNode();
    root.attributes.params = params;
    delete root.attributes.value;
    root.reload();
    if (!root.isExpanded()) root.expand();
  }


}


/**
 *
 */
function makeRequest(params, callback) {
  //
  var url = params.url;
  var options = {};
  var gio = gadgets.io;
  var RequestParameters = gio.RequestParameters;

  options[RequestParameters.METHOD] = gio.MethodType.GET
  options[RequestParameters.CONTENT_TYPE] = gio.ContentType[params.contentType || 'TEXT'];
  if (params['OAUTH_SERVICE_NAME']) {
    options[RequestParameters.AUTHORIZATION] = gio.AuthorizationType.OAUTH;
    options[RequestParameters.OAUTH_SERVICE_NAME] = params['OAUTH_SERVICE_NAME'];
  }
  // options[RequestParameters.REFRESH_INTERVAL] = 180;

  gio.makeRequest(url, function(response) {
    if (response.oauthApprovalUrl) {
      var dialog;
      var popup = new gadgets.oauth.Popup(
        response.oauthApprovalUrl,
        null,
        function() {}, // onOpen
        function() { // onClose
          if (dialog) dialog.close();
          makeRequest(params, callback);
        }
      );
      var approve = popup.createApprovedOnClick();
      dialog = new Ext.Window({
        title : 'OAuth authorization required',
        html : 'Authorization is required to access the url.',
        width : 200,
        modal : true,
        plain : true,
        closable : false,
        buttons : [{
          text : 'Authorize',
          handler : popup.createOpenerOnClick()
        }, {
          text : 'Cancel',
          handler : function() {
            dialog.close();
            callback.onFailure();
          }
        }]
      });
      dialog.show();
    } else if (response.rc == undefined || response.text == null) {
      callback.onFailure('Invalid Response');
    } else if (response.rc != 200) {
      callback.onFailure('Error: '+response.rc);
    } else {
      callback.onSuccess(response.data || response.text);
    }
  }, options);
}

});
